package com.vcms.cms.dao.impl;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Iterator;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.vcms.cms.dao.HibernateDaoSupport;
import com.vcms.common.util.PageBean;


@Component
public abstract class HibernateDaoSupportImpl<T> implements
		HibernateDaoSupport<T> {
	private SessionFactory sessionFactory;
	private String subHql = "";

	public HibernateDaoSupportImpl() {
		// 判断是否有isActivated这个属性
		try {
			getType().getMethod("setIsActivated", Boolean.class);
			subHql = " and model.isActivated=true";
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			subHql = "";
		}
	}

	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;

	}

	@Override
	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	@Override
	public boolean save(T transientInstance) {
		if (subHql.length() < 1) {
			getSession().save(transientInstance);
			return true;
		}
		try {
			Method method = getType()
					.getMethod("setIsActivated", Boolean.class);
			method.invoke(transientInstance, true);
			getSession().save(transientInstance);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public boolean update(T transientInstance) {
		if (subHql.length() < 1) {
			getSession().update(transientInstance);
			return true;
		}
		try {
			Method method = getType()
					.getMethod("setIsActivated", Boolean.class);
			method.invoke(transientInstance, true);
			getSession().update(transientInstance);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public int delete(int id) {
		if (subHql.length() < 1) {
			getSession().delete(findById(id));
			return 1;
		}
		try {
			Object transientInstance = getType().newInstance();
			transientInstance = findById(id);
			Method method = getType()
					.getMethod("setIsActivated", Boolean.class);
			method.invoke(transientInstance, false);
			return 1;
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}

	@Override
	public int delete(T transientInstance) {
		if (subHql.length() < 1) {
			getSession().delete(transientInstance);
			return 1;
		}
		try {
			Method method = getType()
					.getMethod("setIsActivated", Boolean.class);
			method.invoke(transientInstance, false);
			getSession().update(transientInstance);
			return 1;
		} catch (Exception e) {
			e.printStackTrace();
			return 0;
		}
	}

	@Override
	public void saveOrUpdate(T transientInstance) {
		getSession().saveOrUpdate(transientInstance);
	}

	@Override
	@SuppressWarnings("unchecked")
	public T findById(Integer id) {
		return (T) getSession().get(getType(), id);
	}

	@Override
	public T findByUniqueProperty(String propertyName, Object value) {
		Collection<T> collection = findByProperty(propertyName, value);
		Iterator<T> it = collection.iterator();
		return it.hasNext() ? it.next() : null;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Collection<T> findByProperty(String propertyName, Object value) {
		String queryString = "from " + getType().getName()
				+ " as model where model." + propertyName + "=?" + subHql;
		Query query = getSession().createQuery(queryString);
		query.setParameter(0, value);
		return query.list();
	}

	@Override
	@SuppressWarnings("unchecked")
	public Collection<T> findByProperties(String[] propertyNames,
			Object[] values) {
		if (propertyNames.length != values.length) {
			System.out.println("**propertyNames.length != values.length**");
			return null;
		}
		String properties = "";
		// 拼凑属性
		for (int i = 0; i < propertyNames.length - 1; i++) {
			properties = properties + " model." + propertyNames[i] + "=? and";
		}
		// 最后一个属性后没有and
		properties = properties + " model."
				+ propertyNames[propertyNames.length - 1] + "=?";

		String queryString = "from " + getType().getName() + " as model where"
				+ properties + subHql;

		Query query = getSession().createQuery(queryString);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query.list();
	}

	@Override
	@SuppressWarnings("unchecked")
	public Collection<T> findByProperties(String[] propertyNames,
			Object[] values, Boolean increase, String orderpropertyName,
			PageBean pageBean) {
		if (propertyNames.length != values.length) {
			System.out.println("**propertyNames.length != values.length**");
			return null;
		}
		pageBean.setTotalRow(getAmount(propertyNames, values));
		String properties = "";
		// 拼凑属性
		for (int i = 0; i < propertyNames.length - 1; i++) {
			properties = properties + " model." + propertyNames[i] + "=? and";
		}
		// 最后一个属性后没有and
		properties = properties + " model."
				+ propertyNames[propertyNames.length - 1] + "=?";

		String queryString = "from " + getType().getName() + " as model where"
				+ properties + subHql + " order by " + orderpropertyName + " ";
		queryString += increase == true ? "asc" : "desc";

		Query query = getSession().createQuery(queryString);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		query.setMaxResults(pageBean.getPageSize()).setFirstResult(
				pageBean.getNextResult());
		return query.list();
	}

	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Collection<T> searchByProperty(String propertyName, Object value) {
		try {
			Class c = getType().getMethod(
					"get" + propertyName.substring(0, 1).toUpperCase()
							+ propertyName.substring(1)).getReturnType();
			if (c.equals(String.class)) {
				String queryString = "from " + getType().getName()
						+ " as model where model." + propertyName + " like "
						+ "?" + subHql;
				Query query = getSession().createQuery(queryString);
				query.setParameter(0, "%" + value + "%");
				query.setMaxResults(10);
				return query.list();
			} else {

				String queryString = "from " + getType().getName()
						+ " as model where model." + propertyName + "=" + "?"
						+ subHql;
				Query query = getSession().createQuery(queryString);
				query.setParameter(0, Integer.parseInt((String) value));
				query.setMaxResults(10);
				return query.list();
			}

		} catch (Exception e) {
		}
		return null;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Collection<T> findAll() {
		String queryString = "from " + getType().getName()
				+ " as model where 1=1" + subHql;
		Query query = getSession().createQuery(queryString);
		return query.list();
	}

	@Override
	public long getAmount() {
		String queryString = "select count(*) from " + getType().getName()
				+ " as model where 1=1" + subHql;
		Query query = getSession().createQuery(queryString);
		long count = (Long) query.uniqueResult();
		return count;
	}

	@Override
	public long getAmount(String propertyName, Object value) {
		String queryString = "select count(*) from " + getType().getName()
				+ " as model where model." + propertyName + "=?" + subHql;
		Query query = getSession().createQuery(queryString);
		query.setParameter(0, value);
		long count = (Long) query.uniqueResult();
		return count;
	}

	@Override
	public long getAmount(String[] propertyNames, Object[] values) {
		if (propertyNames.length != values.length) {
			System.out.println("**propertyNames.length != values.length**");
			return 0;
		}
		String properties = "";
		for (int i = 0; i < propertyNames.length - 1; i++) {
			properties = properties + " model." + propertyNames[i] + "=? and";
		}
		// 最后一个属性后没有and
		properties = properties + " model."
				+ propertyNames[propertyNames.length - 1] + "=?";

		String queryString = "select count(*) from " + getType().getName()
				+ " as model where " + properties + subHql;
		Query query = getSession().createQuery(queryString);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		long count = (Long) query.uniqueResult();
		return count;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Collection<T> findByPage(PageBean pageBean) {
		pageBean.setTotalRow(getAmount());
		String queryString = "from " + getType().getName()
				+ " as model where 1=1" + subHql;
		Query query = getSession().createQuery(queryString);
		query.setMaxResults(pageBean.getPageSize()).setFirstResult(
				pageBean.getNextResult());
		return query.list();
	}

	@Override
	@SuppressWarnings("unchecked")
	public Collection<T> findByPage(Boolean increase, String orderpropertyName,
			PageBean pageBean) {
		pageBean.setTotalRow(getAmount());
		String queryString = "from " + getType().getName()
				+ " as model where 1=1" + subHql + " order by "
				+ orderpropertyName + " ";
		queryString += increase == true ? "asc" : "desc";
		Query query = getSession().createQuery(queryString);
		query.setMaxResults(pageBean.getPageSize()).setFirstResult(
				pageBean.getNextResult());
		return query.list();
	}

	@Override
	@SuppressWarnings("unchecked")
	public Collection<T> findByPage(String propertyName, Object value,
			PageBean pageBean) {
		pageBean.setTotalRow(getAmount(propertyName, value));
		String queryString = "from " + getType().getName()
				+ " as model where model." + propertyName + "=?" + subHql;
		Query query = getSession().createQuery(queryString).setParameter(0,
				value);
		query.setMaxResults(pageBean.getPageSize()).setFirstResult(
				pageBean.getNextResult());
		return query.list();
	}

	@Override
	@SuppressWarnings("unchecked")
	public Collection<T> findByPage(String propertyName, Object value,
			Boolean increase, String orderpropertyName, PageBean pageBean) {
		pageBean.setTotalRow(getAmount(propertyName, value));
		String queryString = "from " + getType().getName()
				+ " as model where model." + propertyName + "=? " + subHql
				+ " order by model." + orderpropertyName + " ";
		queryString += increase == true ? "asc" : "desc";
		Query query = getSession().createQuery(queryString);
		query.setParameter(0, value).setMaxResults(pageBean.getPageSize())
				.setFirstResult(pageBean.getNextResult());
		return query.list();
	}

	@SuppressWarnings("unchecked")
	public Class<T> getType() {
		Type type = getClass().getGenericSuperclass();
		if (type != null && type instanceof ParameterizedType) {
			Type[] args = ((ParameterizedType) type).getActualTypeArguments();
			if (args != null && args.length > 0) {
				return (Class<T>) args[0];
			}
		}
		return null;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Collection<T> findByPage(String propertyName, Object value,
			PageBean pageBean, Boolean fuzzy) {
		if (fuzzy) {
			pageBean.setTotalRow(getAmount(propertyName, value));
			String queryString = "from " + getType().getName()
					+ " as model where model." + propertyName + " like ? "
					+ subHql;
			Query query = getSession().createQuery(queryString);
			query.setParameter(0, "%" + value + "%")
					.setMaxResults(pageBean.getPageSize())
					.setFirstResult(pageBean.getNextResult());
			return query.list();
		} else
			return findByPage(propertyName, value, pageBean);
	}
}
